﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using StardewModdingAPI;
using StardewModdingAPI.Events;
using StardewValley;
using StardewValley.Menus;

namespace WorseGame.Content
{
    public class 居民假期系统(IMonitor monitor, IModHelper helper)
    {
        public readonly IMonitor 监视器 = monitor;
        public readonly IModHelper 助手 = helper;
        private Dictionary<string, 假期安排> 居民假期表 = new();
        private bool 显示假期界面 = false;
        private Rectangle 假期界面区域;
        private bool 已加载存档 = false;
        public enum 假期类型
        {
            家庭度假,
            个人休息,
            节日准备,
            生病请假,
            工作出差
        }
        public class 假期安排
        {
            public string 居民名称 { get; set; } = "";
            public 假期类型 类型 { get; set; }
            public int 开始日期 { get; set; }
            public int 结束日期 { get; set; }
        }

        public void Initialize()
        {
            助手.Events.GameLoop.DayStarted += 每日开始;
            助手.Events.GameLoop.SaveLoaded += 存档加载;
            助手.Events.GameLoop.ReturnedToTitle += 返回标题;
            助手.Events.Display.RenderedHud += 渲染界面;
            助手.Events.Input.ButtonPressed += 按键按下;
            助手.Events.GameLoop.UpdateTicked += 更新时;
        }

        public void 按键按下(object? sender, ButtonPressedEventArgs e)
        {
            if (e.Button == SButton.F8 && 已加载存档)
            {
                显示假期界面 = !显示假期界面;
                Game1.playSound(显示假期界面 ? "bigSelect" : "bigDeSelect");
            }
        }

        public void 存档加载(object? sender, SaveLoadedEventArgs e)
        {
            已加载存档 = true;
            加载假期数据();
            if (居民假期表.Count == 0)
            {
                生成新的假期安排();
            }
        }

        public void 返回标题(object? sender, ReturnedToTitleEventArgs e)
        {
            已加载存档 = false;
            居民假期表.Clear();
        }

        public void 每日开始(object? sender, DayStartedEventArgs e)
        {
            if (!已加载存档) return;

            检查假期开始结束();
            if (Game1.dayOfMonth == 1)
            {
                生成新的假期安排();
            }

            更新居民位置();
        }

        public void 更新时(object? sender, UpdateTickedEventArgs e)
        {
            if (!已加载存档) return;
            if (e.IsMultipleOf(600))
            {
                更新居民位置();
            }
        }

        private void 检查假期开始结束()
        {
            int 当前日期 = Game1.dayOfMonth;
            var 今天开始假期 = 居民假期表.Values.Where(v => v.开始日期 == 当前日期).ToList();
            var 今天结束假期 = 居民假期表.Values.Where(v => v.结束日期 == 当前日期).ToList();

            foreach (var 假期 in 今天开始假期)
            {
                监视器.Log($"{假期.居民名称} 开始假期：{假期.类型}");
                Game1.addHUDMessage(new HUDMessage($"{假期.居民名称} 开始假期了", 1));
            }

            foreach (var 假期 in 今天结束假期)
            {
                监视器.Log($"{假期.居民名称} 结束假期");
                Game1.addHUDMessage(new HUDMessage($"{假期.居民名称} 假期结束回来了", 2));              
                恢复居民到城镇(假期.居民名称);
            }
        }

        private void 恢复居民到城镇(string 居民名称)
        {
            var npc = Game1.getCharacterFromName(居民名称);
            if (npc != null)
            {
                var 城镇 = Game1.getLocationFromName("Town");
                if (城镇 != null)
                {
                    if (npc.currentLocation != null)
                    {
                        npc.currentLocation.characters.Remove(npc);
                    }
                    if (!城镇.characters.Contains(npc))
                    {
                        城镇.characters.Add(npc);
                        npc.currentLocation = 城镇;
                        int 随机X = Game1.random.Next(30, 50) * 64; 
                        int 随机Y = Game1.random.Next(20, 40) * 64;
                        npc.setTilePosition(随机X / 64, 随机Y / 64);

                        监视器.Log($"恢复 {居民名称} 到城镇位置 ({随机X / 64}, {随机Y / 64})");
                    }
                }
            }
        }

        private void 更新居民位置()
        {
            int 当前日期 = Game1.dayOfMonth;
            var 所有NPC = Utility.getAllCharacters();

            foreach (var npc in 所有NPC)
            {
                if (居民假期表.TryGetValue(npc.Name, out 假期安排? 假期))
                {
                    if (当前日期 >= 假期.开始日期 && 当前日期 <= 假期.结束日期)
                    {
                        npc.currentLocation?.characters.Remove(npc);
                        npc.currentLocation = null;
                    }
                    else if (当前日期 > 假期.结束日期)
                    {
                        居民假期表.Remove(npc.Name);
                    }
                }
            }

            if (已加载存档)
            {
                保存假期数据();
            }
        }

        private void 生成新的假期安排()
        {
            var 所有居民 = 获取所有居民();
            var 新的假期表 = new Dictionary<string, 假期安排>();

            foreach (var 居民 in 所有居民)
            {
                if (Game1.random.NextDouble() < 0.15)
                {
                    var 假期安排 = new 假期安排
                    {
                        居民名称 = 居民,
                        类型 = 获取随机假期类型(),
                        开始日期 = Game1.random.Next(5, 20),
                        结束日期 = 0
                    };
                    int 假期长度 = Game1.random.Next(2, 6);
                    假期安排.结束日期 = 假期安排.开始日期 + 假期长度 - 1;
                    if (假期安排.结束日期 > 28) 假期安排.结束日期 = 28;

                    新的假期表[居民] = 假期安排;
                }
            }

            居民假期表 = 新的假期表;
            保存假期数据();
            监视器.Log($"生成了{居民假期表.Count}个居民的假期安排");
        }

        private List<string> 获取所有居民()
        {
            return new List<string> { "亚历克斯", "艾利欧特", "哈维", "山姆", "塞巴斯蒂安", "谢恩", "阿比盖尔", "艾米丽", "海莉", "莉亚", "玛鲁", "潘妮", "卡洛琳", "克林特", "德米特里厄斯", "矮人", "艾芙琳", "乔治", "格斯", "贾斯", "乔迪", "肯特", "科罗布斯", "刘易斯", "莱纳斯", "玛妮", "潘姆", "皮埃尔", "罗宾", "桑迪", "文森特", "威利", "法师", "雷欧", "门卫", "吉尔", "州长", "爷爷", "冈瑟", "仆从", "马龙", "莫里斯", "齐先生", "贝啼", "蜗牛教授", "菲兹" };

        }

        private 假期类型 获取随机假期类型()
        {
            var 类型列表 = new List<假期类型>
            {
                假期类型.个人休息,
                假期类型.家庭度假,
                假期类型.节日准备,
                假期类型.生病请假,
                假期类型.工作出差
            };
            return 类型列表[Game1.random.Next(类型列表.Count)];
        }

        public void 渲染界面(object? sender, RenderedHudEventArgs e)
        {
            if (显示假期界面 && 已加载存档)
            {
                绘制假期界面(e.SpriteBatch);
            }
        }

        public void 绘制假期界面(SpriteBatch spriteBatch)
        {
            int 界面宽度 = 350;
            int 界面高度 = 400;
            int 界面X = Game1.viewport.Width - 界面宽度 - 20;
            int 界面Y = 100;

            假期界面区域 = new Rectangle(界面X, 界面Y, 界面宽度, 界面高度);

            IClickableMenu.drawTextureBox(spriteBatch, Game1.menuTexture, new Rectangle(0, 256, 60, 60),
                界面X, 界面Y, 界面宽度, 界面高度, Color.White);
            string 标题 = "居民假期安排";
            Vector2 标题尺寸 = Game1.dialogueFont.MeasureString(标题);
            Vector2 标题位置 = new(界面X + (界面宽度 - 标题尺寸.X) / 2, 界面Y + 16);
            Utility.drawTextWithShadow(spriteBatch, 标题, Game1.dialogueFont, 标题位置, Game1.textColor);
            int 当前日期 = Game1.dayOfMonth;
            int 文本Y = 界面Y + 60;
            int 行高 = 25;

            var 当前假期 = 居民假期表.Values.Where(v => 当前日期 >= v.开始日期 && 当前日期 <= v.结束日期).ToList();
            var 即将开始假期 = 居民假期表.Values.Where(v => v.开始日期 > 当前日期).ToList();
            Utility.drawTextWithShadow(spriteBatch, "正在休假：", Game1.smallFont, new Vector2(界面X + 20, 文本Y), Color.Red);
            文本Y += 行高;

            foreach (var 假期 in 当前假期)
            {
                string 状态 = $"{假期.居民名称} ({获取假期类型名称(假期.类型)})";
                Utility.drawTextWithShadow(spriteBatch, 状态, Game1.smallFont, new Vector2(界面X + 30, 文本Y), Color.Orange);
                文本Y += 行高;
            }

            文本Y += 10;
            Utility.drawTextWithShadow(spriteBatch, "即将开始：", Game1.smallFont, new Vector2(界面X + 20, 文本Y), Color.Green);
            文本Y += 行高;

            foreach (var 假期 in 即将开始假期)
            {
                string 状态 = $"{假期.居民名称} ({假期.开始日期}号开始)";
                Utility.drawTextWithShadow(spriteBatch, 状态, Game1.smallFont, new Vector2(界面X + 30, 文本Y), Color.LightBlue);
                文本Y += 行高;
            }         
            string 提示文字 = "按 F8 隐藏";
            Vector2 提示尺寸 = Game1.smallFont.MeasureString(提示文字);
            Utility.drawTextWithShadow(spriteBatch, 提示文字, Game1.smallFont,
                new Vector2(界面X + 界面宽度 - 提示尺寸.X - 15, 界面Y + 界面高度 + 10), Color.Gray);
        }

        private string 获取假期类型名称(假期类型 类型)
        {
            return 类型 switch
            {
                假期类型.家庭度假 => "家庭度假",
                假期类型.个人休息 => "个人休息",
                假期类型.节日准备 => "节日准备",
                假期类型.生病请假 => "生病请假",
                假期类型.工作出差 => "工作出差",
                _ => "假期"
            };
        }

        private void 加载假期数据()
        {
            if (!已加载存档) return;

            try
            {
                string? 假期数据 = 助手.Data.ReadSaveData<string>("ResidentHolidayData");             
            }
            catch (System.Exception ex)
            {
                监视器.Log($"加载假期数据时出错: {ex.Message}", LogLevel.Error);
            }
        }

        private void 保存假期数据()
        {
            if (!已加载存档) return;

            try
            {               
                助手.Data.WriteSaveData("ResidentHolidayData", "active");
            }
            catch (System.Exception ex)
            {
                监视器.Log($"保存假期数据时出错: {ex.Message}", LogLevel.Error);
            }
        }
    }
}